﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO;
using System.Web.Script.Serialization;
using System.Threading;

namespace TStart
{
    public partial class frmMain : Form
    {
        Semaphore semFormOnce;

        bool loadWait = true;
        bool hideState = false;
        bool hideWait = false;
        bool hideForce = false;
        bool showForce = false;
        int hideTimeout = 0;
        string configFileName = Application.StartupPath + "\\config.json";
        ImageList imageListLargeIcon = new ImageList();
        ImageList imageListSmallIcon = new ImageList();

        TStartConfig tStartConfig = new TStartConfig();

        public frmMain(Semaphore sem)
        {
            InitializeComponent();

            semFormOnce = sem;
            tStartConfig.Title = this.Text;

            this.TopMost = true;
            imageListLargeIcon.ColorDepth = ColorDepth.Depth32Bit;
            imageListLargeIcon.ImageSize = new Size(32, 32);
            imageListSmallIcon.ColorDepth = ColorDepth.Depth32Bit;
            imageListSmallIcon.ImageSize = new Size(16, 16);
        }

        ListView TabControlGroupsAddItem(string groupName, bool isFocus)
        {
            tabControlGroups.TabPages.Add(groupName);
            TabPage tabPage = tabControlGroups.TabPages[tabControlGroups.TabPages.Count - 1];

            ListView listView = new ListView();
            tabPage.Controls.Add(listView);
            listView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
            listView.Size = tabPage.ClientSize;
            listView.BorderStyle = BorderStyle.None;

            listView.AllowDrop = true;
            listView.ItemDrag += ListViewApps_ItemDrag;
            listView.DragEnter += ListViewApps_DragEnter;
            listView.DragOver += ListViewApps_DragOver;
            listView.DragDrop += ListViewApps_DragDrop;
            listView.DragLeave += ListViewApps_DragLeave;
            listView.MouseUp += ListViewApps_MouseUp;
            listView.DoubleClick += ListViewApps_DoubleClick;
            listView.ListViewItemSorter = new ListViewIndexComparer();
            listView.View = (View)tStartConfig.View; // View.SmallIcon;
            listView.LargeImageList = imageListLargeIcon;
            listView.SmallImageList = imageListSmallIcon;
            listView.FullRowSelect = true;
            listView.Columns.Add("项目", 120);
            listView.Columns.Add("路径", 200);

            if (isFocus)
            {
                tabControlGroups.SelectedIndex = tabControlGroups.TabPages.Count - 1;
            }
            return listView;
        }

        void ListViewAppsAddItem(ListView listView, AppsItem appItem, bool isFocus)
        {
            for (int i = 0; i < listView.Items.Count; i++)
            {
                if (((AppsItem)listView.Items[i].Tag).Path == appItem.Path)
                {
                    if (isFocus)
                    {
                        listView.Focus();
                        for (int j = 0; j < listView.SelectedItems.Count; j++)
                        {
                            listView.SelectedItems[j].Selected = false;
                        }
                        listView.Items[i].Selected = true;
                        listView.Items[i].EnsureVisible();
                        listView.Items[i].Focused = true;
                    }
                    return;
                }
            }
            try
            {
                ListViewItem item = new ListViewItem(appItem.Name);
                item.Tag = appItem;
                item.ImageKey = imageListLargeIcon.Images.Count.ToString();
                imageListLargeIcon.Images.Add(item.ImageKey, GetSystemIcon.GetIconByFileName(appItem.Icon, true));
                imageListSmallIcon.Images.Add(item.ImageKey, GetSystemIcon.GetIconByFileName(appItem.Icon, false));
                item.SubItems.Add(appItem.Path);
                listView.Items.Add(item);
                if (isFocus)
                {
                    for (int j = 0; j < listView.SelectedItems.Count; j++)
                    {
                        listView.SelectedItems[j].Selected = false;
                    }
                    item.Selected = true;
                    item.EnsureVisible();
                    item.Focused = true;
                }
            }
            catch
            {
            }
        }

        void ListViewAppsUpdateItem(ListViewItem item, AppsItem appItem)
        {
            try
            {
                item.Tag = appItem;
                item.Text = appItem.Name;
                imageListLargeIcon.Images.RemoveByKey(item.ImageKey);
                imageListLargeIcon.Images.Add(item.ImageKey, GetSystemIcon.GetIconByFileName(appItem.Icon, true));
                imageListSmallIcon.Images.RemoveByKey(item.ImageKey);
                imageListSmallIcon.Images.Add(item.ImageKey, GetSystemIcon.GetIconByFileName(appItem.Icon, false));
                item.SubItems[1].Text = appItem.Path;
            }
            catch
            {
            }
        }

        void TStartRootLoad()
        {
            if (!System.IO.File.Exists(configFileName))
            {
                return;
            }

            try
            {
                string json = System.IO.File.ReadAllText(configFileName, TxtFileEncoder.GetEncoding(configFileName));

                JavaScriptSerializer js = new JavaScriptSerializer();
                TStartRoot tStartRoot = js.Deserialize<TStartRoot>(json);

                tStartConfig = tStartRoot.config;
                this.Location = new Point(tStartConfig.X, tStartConfig.Y);
                this.Size = new Size(tStartConfig.Width, tStartConfig.Height);
                this.Text = tStartConfig.Title;
                for (int i = 0; i < tStartRoot.Groups.Count; i++)
                {
                    ListView listView = TabControlGroupsAddItem(tStartRoot.Groups[i].Name, false);
                    for (int j = 0; j < tStartRoot.Groups[i].Apps.Count; j++)
                    {
                        ListViewAppsAddItem(listView, tStartRoot.Groups[i].Apps[j], false);
                    }
                }
            }
            catch
            {

            }
        }

        void TStartRootSave()
        {
            TStartRoot tStartRoot = new TStartRoot();

            tStartConfig.X = this.Location.X;
            tStartConfig.Y = this.Location.Y;
            tStartConfig.Width = this.Size.Width;
            tStartConfig.Height = this.Size.Height;
            tStartRoot.config = tStartConfig;
            tStartRoot.Groups = new List<GroupsItem>();
            for (int i = 0; i < tabControlGroups.TabPages.Count; i++)
            {
                GroupsItem groupItem = new GroupsItem();
                tStartRoot.Groups.Add(groupItem);

                groupItem.Name = tabControlGroups.TabPages[i].Text;
                ListView listView = (ListView)tabControlGroups.TabPages[i].Controls[0];
                tStartRoot.Groups[i].Apps = new List<AppsItem>();
                for (int j = 0; j < listView.Items.Count; j++)
                {
                    groupItem.Apps.Add((AppsItem)listView.Items[j].Tag);
                }
            }

            JavaScriptSerializer js = new JavaScriptSerializer();
            System.IO.File.WriteAllText(configFileName, Misc.json_format(js.Serialize(tStartRoot)));
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            TStartRootLoad();
            loadWait = false;
        }

        private void ListViewApps_DoubleClick(object sender, EventArgs e)
        {
            ListView listView = (ListView)sender;

            ListViewAppsStart(listView, false);
        }

        private void ListViewApps_ItemDrag(object sender, ItemDragEventArgs e)
        {
            ListView listView = (ListView)sender;
            listView.DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void ListViewApps_DragEnter(object sender, DragEventArgs e)
        {
            try
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    e.Effect = DragDropEffects.Copy;
                }
                else if (e.Data.GetDataPresent(DataFormats.Serializable))
                {
                    ListViewItem item = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
                    e.Effect = DragDropEffects.Move;
                }
                else
                {
                    e.Effect = DragDropEffects.None;
                }
            }
            catch
            {

            }
        }

        private void ListViewApps_DragOver(object sender, DragEventArgs e)
        {
            try
            {
                ListView listView = (ListView)sender;

                if (e.Effect == DragDropEffects.Move)
                {
                    ListViewItem item = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
                    Point pt = listView.PointToClient(new Point(e.X, e.Y));

                    int targetIndex = listView.InsertionMark.NearestIndex(pt);
                    if (targetIndex > -1)
                    {
                        Rectangle itemBounds = listView.GetItemRect(targetIndex);
                        if (itemBounds.Contains(pt) && (pt.X > itemBounds.Left + (itemBounds.Width / 2)))
                        {
                            listView.InsertionMark.AppearsAfterItem = true;
                        }
                        else
                        {
                            listView.InsertionMark.AppearsAfterItem = false;
                        }
                    }
                    listView.InsertionMark.Index = targetIndex;
                }
            }
            catch
            {
            }
        }

        private void ListViewApps_DragLeave(object sender, EventArgs e)
        {
            ListView listView = (ListView)sender;

            listView.InsertionMark.Index = -1;
        }

        private void ListViewApps_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                ListView listView = (ListView)sender;

                if (e.Effect == DragDropEffects.Move)
                {
                    int targetIndex = listView.InsertionMark.Index;
                    if (targetIndex == -1)
                    {
                        return;
                    }
                    if (listView.InsertionMark.AppearsAfterItem)
                    {
                        targetIndex++;
                    }

                    ListViewItem item = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
                    listView.Items.Insert(targetIndex, (ListViewItem)item.Clone());
                    listView.Items.Remove(item);
                }
                else if (e.Effect == DragDropEffects.Copy)
                {
                    String[] FileNames = e.Data.GetData(DataFormats.FileDrop, false) as String[];

                    for (int i = 0; i < FileNames.Length; i++)
                    {
                        AppsItem appItem = Misc.PathAppsItem(FileNames[i]);

                        ListViewAppsAddItem(listView, appItem, true);
                    }
                }

                TStartRootSave();
            }
            catch
            {

            }
        }

        private class ListViewIndexComparer : System.Collections.IComparer
        {
            public int Compare(object x, object y)
            {
                return ((ListViewItem)x).Index - ((ListViewItem)y).Index;
            }
        }

        private void ListViewApps_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ListView listView = (ListView)sender;
                ListViewItem item = listView.GetItemAt(e.X, e.Y);
                bool itemsEnabled = listView.SelectedItems.Contains(item);
                for (int i = 1; i < contextMenuStripApps.Items.Count; i++)
                {
                    contextMenuStripApps.Items[i].Enabled = itemsEnabled;
                }

                ToolStripDropDownItem dropDownItem = (ToolStripDropDownItem)contextMenuStripApps.Items[3];
                dropDownItem.Enabled = false;
                if (itemsEnabled && tabControlGroups.TabCount > 1)
                {
                    dropDownItem.Enabled = true;
                    dropDownItem.DropDownItems.Clear();
                    for (int i = 0; i < tabControlGroups.TabCount; i++)
                    {
                        ToolStripItem toolStripItem = dropDownItem.DropDownItems.Add(tabControlGroups.TabPages[i].Text);
                        toolStripItem.Enabled = (i != tabControlGroups.SelectedIndex);
                        toolStripItem.Tag = tabControlGroups.TabPages[i].Controls[0];
                    }
                }

                contextMenuStripApps.Show(listView, e.Location);
            }
        }

        private void TabControlGroups_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                for (int i = 0; i < tabControlGroups.TabPages.Count; i++)
                {
                    if (tabControlGroups.GetTabRect(i).Contains(new Point(e.X, e.Y)))
                    {
                        tabControlGroups.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        private void TabControlGroups_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                for (int i = 0; i < tabControlGroups.TabPages.Count; i++)
                {
                    if (tabControlGroups.GetTabRect(i).Contains(new Point(e.X, e.Y)))
                    {
                        if (tabControlGroups.SelectedIndex == i)
                        {
                            contextMenuStripGroups.Items[1].Enabled = true;
                            contextMenuStripGroups.Items[2].Enabled = true;
                            contextMenuStripGroups.Show(tabControlGroups, e.Location);
                        }
                        break;
                    }
                }
            }
        }

        private void FrmMain_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                contextMenuStripGroups.Items[1].Enabled = false;
                contextMenuStripGroups.Items[2].Enabled = false;
                contextMenuStripGroups.Show(tabControlGroups, e.Location);
            }
        }

        private void ToolStripMenuItemGroupsNew_Click(object sender, EventArgs e)
        {
            TabControlGroupsAddItem("新分组", true);
            TStartRootSave();
        }

        private void ToolStripMenuItemGroupsRename_Click(object sender, EventArgs e)
        {
            Rectangle rect = tabControlGroups.GetTabRect(tabControlGroups.SelectedIndex);
            textBoxTab.SetBounds(rect.X + 6, rect.Y + 2, rect.Width - 8, rect.Height);
            textBoxTab.Text = tabControlGroups.SelectedTab.Text;
            textBoxTab.SelectionStart = 0;
            textBoxTab.SelectAll();
            textBoxTab.Visible = true;
            textBoxTab.Focus();
        }

        private void ToolStripMenuItemGroupsDelete_Click(object sender, EventArgs e)
        {
            tabControlGroups.TabPages.Remove(tabControlGroups.SelectedTab);
            TStartRootSave();
        }

        private void TextBoxTab_Leave(object sender, EventArgs e)
        {
            string strTmp = textBoxTab.Text.Trim();
            if (strTmp.Length > 0)
            {
                tabControlGroups.SelectedTab.Text = strTmp;
                TStartRootSave();
            }
            textBoxTab.Visible = false;
        }

        private void TimerHide_Tick(object sender, EventArgs e)
        {
            if (semFormOnce.WaitOne(1))
            {
                NotifyIcon_DoubleClick(null, null);
            }

            if (this.WindowState == FormWindowState.Normal)
            {
                Point pt = Cursor.Position;
                Rectangle rect = new Rectangle(this.Location, this.Size);

                if (!hideState)
                {
                    if (rect.Contains(pt))
                    {
                        hideWait = false;
                    }

                    if ((this.Location.Y < Screen.GetBounds(this).Top + 5)
                        && (hideForce
                        || ((!rect.Contains(pt)) && (!hideWait) && (!showForce)
                         && (!contextMenuStripGroups.Visible) && (!contextMenuStripApps.Visible))))
                    {
                        hideTimeout++;
                        if (hideTimeout >= 3)
                        {
                            hideTimeout = 0;
                            hideState = true;
                            this.Location = new Point(this.Location.X, -this.Height/* + ((this.Width - this.ClientSize.Width) / 2 + 1)*/);
                        }
                    }
                    else
                    {
                        hideTimeout = 0;
                    }
                }
                else
                {
                    rect.Y = Screen.GetBounds(this).Top;
                    rect.Height = 1;
                    if (rect.Contains(pt))
                    {
                        hideTimeout++;
                        if (hideTimeout >= 3)
                        {
                            hideTimeout = 0;
                            hideState = false;
                            this.TopMost = true;
                            this.Location = new Point(this.Location.X, Screen.GetBounds(this).Top);
                        }
                    }
                    else
                    {
                        hideTimeout = 0;
                        hideForce = false;
                    }
                }
            }
        }

        private void FrmMain_Move(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal && !hideState && !loadWait)
            {
                TStartRootSave();
            }
        }

        private void FrmMain_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal && !hideState && !loadWait)
            {
                TStartRootSave();
            }
        }

        private void ToolStripMenuItemAppsNew_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;
            frmEdit dlgEdit = new frmEdit();
            showForce = true;

            if (dlgEdit.ShowDialog() == DialogResult.OK)
            {
                ListViewAppsAddItem(listView, dlgEdit.AppsItemGet(), true);
                TStartRootSave();
            }

            showForce = false;
        }

        private void ToolStripMenuItemAppsEdit_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;
            frmEdit dlgEdit = new frmEdit();
            showForce = true;

            ListViewItem item = listView.SelectedItems[0];
            dlgEdit.AppsItemSet((AppsItem)item.Tag);
            if (dlgEdit.ShowDialog() == DialogResult.OK)
            {
                ListViewAppsUpdateItem(item, dlgEdit.AppsItemGet());
                TStartRootSave();
            }

            showForce = false;
        }

        private void ToolStripMenuItemAppsDelete_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;

            while (listView.SelectedItems.Count > 0)
            {
                listView.SelectedItems[0].Remove();
            }
            TStartRootSave();
        }

        private void ToolStripMenuItemAppsMove_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;
            ListView listViewDst = (ListView)e.ClickedItem.Tag;

            while (listView.SelectedItems.Count > 0)
            {
                listViewDst.Items.Add((ListViewItem)listView.SelectedItems[0].Clone());
                listView.SelectedItems[0].Remove();
            }
            TStartRootSave();

            hideWait = true;
        }

        private void ListViewAppsStart(ListView listView, bool isAdmin)
        {
            for (int i = 0; i < listView.SelectedItems.Count; i++)
            {
                try
                {
                    AppsItem item = (AppsItem)listView.SelectedItems[i].Tag;
                    hideForce = tStartConfig.HideAfterOpen;

                    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
                    startInfo.FileName = item.Path;
                    startInfo.UseShellExecute = true;
                    startInfo.WorkingDirectory = Misc.PathFilePath(item.Path);
                    startInfo.Arguments = String.Join(" ", item.Args);
                    if (isAdmin)
                    {
                        startInfo.Verb = "runas";
                    }
                    System.Diagnostics.Process.Start(startInfo);
                }
                catch
                {

                }
            }
        }

        private void ToolStripMenuItemAppsOpen_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;

            ListViewAppsStart(listView, false);
        }

        private void ToolStripMenuItemAppsRunAdmin_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;

            ListViewAppsStart(listView, true);
        }

        private void ToolStripMenuItemAppsLocation_Click(object sender, EventArgs e)
        {
            ListView listView = (ListView)contextMenuStripApps.SourceControl;
            string strPath = ((AppsItem)listView.SelectedItems[0].Tag).Path;

            hideForce = true;
            System.Diagnostics.Process.Start("Explorer.exe", "/select," + strPath);
        }


        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.WindowState != FormWindowState.Minimized)
            {
                e.Cancel = true;
                this.Visible = false;
                this.WindowState = FormWindowState.Minimized;
            }
        }

        private void NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            if (this.WindowState != FormWindowState.Normal)
            {
                this.WindowState = FormWindowState.Normal;
                this.Visible = true;
                hideWait = true;
            }
            if (hideState)
            {
                hideWait = true;
                hideState = false;
                //this.Visible = true;
                this.Location = new Point(this.Location.X, Screen.GetBounds(this).Top);
            }
        }

        private void ToolStripMenuItemShow_Click(object sender, EventArgs e)
        {
            NotifyIcon_DoubleClick(null, null);
        }

        private void ToolStripMenuItemConfig_Click(object sender, EventArgs e)
        {
            frmConfig dlgConfig = new frmConfig();

            dlgConfig.ConfigSet(tStartConfig);
            if (dlgConfig.ShowDialog() == DialogResult.OK)
            {
                tStartConfig = dlgConfig.ConfigGet();

                this.Text = tStartConfig.Title;
                for (int i = 0; i < tabControlGroups.TabCount; i++)
                {
                    ListView listView = (ListView)tabControlGroups.TabPages[i].Controls[0];
                    listView.View = (View)tStartConfig.View; // View.SmallIcon;
                }
            }
        }

        private void ToolStripMenuItemExit_Click(object sender, EventArgs e)
        {
            this.Visible = false;
            this.WindowState = FormWindowState.Minimized;
            this.Close();
        }
    }

}
